# _*_ coding utf-8 _*_
# FILENAME：.py
# DESCRIPTION:
# AUTH:
# DATE: 2022/6/82:45 下午

import traceback
import pandas as pd
import logging

from sqlalchemy import asc

from models.baseModel import get_session
from models.scheduleModel import ScheduleModel


class CommonUtils:
    # Method for making car dataframe
    @staticmethod
    def make_car_df(BOM,
                    car_part_df):
        '''
        注意: 计算car_df时需要优先计算car_part_df

        BOM: BOM表
        car_part_df: 零件信息相关表
        '''
        # Find car IDs
        car_ids = []
        all_car_ids = list(BOM["car_model"])
        for car_id in all_car_ids:
            if car_id in car_ids:
                pass
            else:
                car_ids.append(car_id)

        # Find car part IDs per car model and number required
        car_part_ids = []
        for car_id in car_ids:
            indices = [i for i, x in enumerate(list(BOM["car_model"])) if x == car_id]
            part_id_and_number = []
            for i in indices:
                if BOM["part_code"][i] in list(car_part_df["ID"]):
                    part_id_and_number.append((BOM["part_code"][i], BOM["per_number"][i]))
            car_part_ids.append(tuple(part_id_and_number))

        # Fix car IDs
        for i in range(len(car_ids)):
            car_ids[i] = car_ids[i].replace(".", "")

        # Make dataframe
        car_df = pd.DataFrame({"Car type": car_ids, "Car parts": car_part_ids})
        return car_df

    # Method for making car part dataframe
    @staticmethod
    def get_car_part_df(carPartDetails,
                         carPartPositions,
                         ):
        '''
        carPartDetails: 零件基础信息表
        carPartPositions: 零件装配延误时间
        '''
        # Find car part IDs
        car_part_ids = list(carPartDetails["code"])

        # Find car part names
        car_part_names = list(carPartDetails["name"])

        # Find supplier names
        car_part_supplierNames = list(carPartDetails["supplier_name"])

        # Find stockpile lower limit
        car_part_stockpileLowerLimits = list(carPartDetails["safety_stock"])

        # Find stockpile upper limit
        car_part_stockpileUpperLimits = list(carPartDetails["max_stock"])

        # Find unloading crossing
        car_part_unloadingCrossings = list(carPartDetails["unloading_crossing"])

        # Find packing type
        car_part_packingTypes = list(carPartDetails["packaging_type"])

        # Find packing constraint
        car_part_packingConstraints = list(carPartDetails["material_rack_pallet_adapted"])

        # Find SNP
        car_part_SNPs = list(carPartDetails["snp"])

        # Find dimensions
        lengths = list(carPartDetails["length"])
        widths = list(carPartDetails["width"])
        heights = list(carPartDetails["height"])
        car_part_dimensions = []
        for i in range(len(lengths)):
            if heights[i] > 2400:
                if heights[i] > 9600:
                    logging.warning(f"{car_part_ids[i]} is height( {heights[i]} ) too big, ")
                else:
                    car_part_dimensions.append((heights[i], widths[i], lengths[i]))
            else:
                car_part_dimensions.append((lengths[i], widths[i], heights[i]))

                # Find arrival time modifier
        car_part_arrivalTimeModifiers = []
        for car_part in car_part_ids:
            index = carPartPositions.index[carPartPositions["parts_code"] == car_part].tolist()[0]
            car_part_arrivalTimeModifiers.append(carPartPositions["time"][index])

        # Make dataframe
        car_part_df = pd.DataFrame({"ID": car_part_ids, "Name": car_part_names, "Supplier": car_part_supplierNames,
                                    "Lower stockpile limit": car_part_stockpileLowerLimits,
                                    "Upper stockpile limit": car_part_stockpileUpperLimits,
                                    "Unloading crossing": car_part_unloadingCrossings,
                                    "Packing type": car_part_packingTypes,
                                    "Packing constraint": car_part_packingConstraints, "SNP": car_part_SNPs,
                                    "Dimensions": car_part_dimensions,
                                    "Arrival time modifier": car_part_arrivalTimeModifiers})
        return car_part_df

    @staticmethod
    def supplier_information_df(_supplier_names,
                                loading_times,
                                distance_matrix_df,
                                time_matrix_df,
                                ):
        """
        distance_matrix_df: 距离矩阵
        time_matrix_df: 时间矩阵
        supplier_names: 供应商地址
        loading_times: 装载时间
        """
        # Find supplier names
        supplier_names = _supplier_names["supplier_name"].values.tolist()

        # Find supplier addresses
        supplier_addresses = _supplier_names["supplier_address"].values.tolist()

        # Find supplier loading times
        supplier_loading_times = []
        for supplier in supplier_names:
            try:
                index = loading_times.index[loading_times["work_site"] == supplier].tolist()[0]
                supplier_loading_times.append(loading_times["work_time"][index])
            except Exception:
                logging.warning(f"{supplier} is not in loading_times")
                supplier_loading_times.append(0)

        # Find distances to factories (Currently missing data on first and third factories, so using second only)
        # First factory: , index-
        # Second factory: 二工厂, index=0
        # Third factory: , index=
        distances_firstFactory = []
        distances_secondFactory = []
        distances_thirdFactory = []
        for supplier in supplier_names:
            try:
                distances_firstFactory.append(distance_matrix_df[supplier][0])
                distances_secondFactory.append(distance_matrix_df[supplier][0])
                distances_thirdFactory.append(distance_matrix_df[supplier][0])
            except Exception:
                logging.error(f"{supplier} is not in distance_matrix_df")
                logging.error(traceback.format_exc())

        # Find travel time to factories (Currently missing data on first and third factories, so using second only)
        # First factory: , index=
        # Second factory: 二工厂, index=0
        # Third factory: , index=
        travelTimes_firstFactory = []
        travelTimes_secondFactory = []
        travelTimes_thirdFactory = []
        for supplier in supplier_names:
            try:
                travelTimes_firstFactory.append(time_matrix_df[supplier][0])
                travelTimes_secondFactory.append(time_matrix_df[supplier][0])
                travelTimes_thirdFactory.append(time_matrix_df[supplier][0])
            except:
                logging.error(f"{supplier} is not in time_matrix_df")
                logging.error(traceback.format_exc())

        # Make dateframe
        supplier_information_df = pd.DataFrame({"Supplier name": supplier_names, "Loading time": supplier_loading_times,
                                                "Travel time (first factory)": travelTimes_firstFactory,
                                                "Travel time (second factory)": travelTimes_secondFactory,
                                                "Travel time (third factory)": travelTimes_thirdFactory,
                                                "Distance (first factory)": distances_firstFactory,
                                                "Distance (second factory)": distances_secondFactory,
                                                "Distance (third factory)": distances_thirdFactory,
                                                "Address": supplier_addresses})
        return supplier_information_df

    def find_latest_active_worktime(self, factory_id, order_type):
        session = get_session()
        schedule_list = session.query(ScheduleModel).filter(ScheduleModel.factory_id == factory_id).filter(ScheduleModel.order_type == order_type).\
            order_by(asc(ScheduleModel.begin_time)).all()
        session.close()

        result = {"work_time": {"up_time": [], "down_time": []}}
        for schedule in schedule_list:
            time_dict = {"start": schedule.begin_time[:5], "end": schedule.end_time[:5]}
            if schedule.work_type == "上班时间":
                result["work_time"]["up_time"].append(time_dict)
            else:
                result["work_time"]["down_time"].append(time_dict)
        return result
